package com.snake;

import android.graphics.Canvas;
import android.graphics.Point;

// 蛇
class Snake {
    private SnakeBody mCauda;   // 蛇尾
    private int mDirection;     // 移动方向
    private SnakeBody mHead;    // 蛇头

    /**
     * 构造方法。
     * @param drawer    绘图者
     */
    public Snake(Canvas drawer) {
        // 初始化成员
        final Point caudaPos = new Point(0, 0);
        mHead = mCauda = new SnakeBody(drawer, caudaPos, SnakeBody.Type.SNAKE);
        mDirection = Const.DIRECTION_DOWN;
    }

    /**
     * 吃果子，即将果子放到蛇尾。
     * @param apple 果子
     */
    public void eat(SnakeBody apple) {
        // 设置吃到的果子的位置
        final Point position = new Point(mHead.getPosition());
        switch (mDirection) {
            case Const.DIRECTION_DOWN:
                position.y++;
                break;
            case Const.DIRECTION_LEFT:
                position.x--;
                break;
            case Const.DIRECTION_RIGHT:
                position.x++;
                break;
            case Const.DIRECTION_UP:
                position.y--;
                break;
        }
        apple.setPosition(position);

        // 改变果子的类型
        apple.setType(SnakeBody.Type.SNAKE);

        // 重绘蛇头和果子
        mHead.draw();
        apple.draw();

        // 将吃到的果子变成蛇头
        mHead.setNext(apple);
        mHead = apple;
    }

    /**
     * 获取蛇头。
     * @return 蛇头
     */
    public SnakeBody getHead() {
        return mHead;
    }

    /**
     * 移动。
     * @return 蛇头碰到自身或游戏区域边界则返回 true，否则返回 false
     */
    public boolean move() {
        // 计算蛇尾的新位置并抹除蛇尾
        final Point point = new Point(mHead.getPosition());
        switch (mDirection) {
            case Const.DIRECTION_DOWN:
                if (point.y + 1 >= Const.GAME_BOARD_GRID_COUNT_V) {
                    // 如果蛇头超出游戏区域下边界，则返回
                    return true;
                }
                mCauda.erase();
                point.y++;
                break;
            case Const.DIRECTION_LEFT:
                if (point.x - 1 < 0) {
                    // 如果蛇头超出游戏区域左边界，则返回
                    return true;
                }
                mCauda.erase();
                point.x--;
                break;
            case Const.DIRECTION_RIGHT:
                if (point.x + 1 >= Const.GAME_BOARD_GRID_COUNT_H) {
                    // 如果蛇头超出游戏区域右边界，则返回
                    return true;
                }
                mCauda.erase();
                point.x++;
                break;
            case Const.DIRECTION_UP:
                if (point.y - 1 < 0) {
                    return true;    // 如果蛇头超出游戏区域上边界，则返回
                }
                mCauda.erase();
                point.y--;
                break;
        }
        mCauda.setPosition(point);

        // 将蛇尾的下一个结点设置为蛇尾、原蛇尾设置成蛇头
        mHead.setNext(mCauda);
        mHead = mCauda;
        mCauda = mCauda.getNext();
        mHead.setNext(null);
        mHead.draw();

        // 检查蛇头是否碰到蛇身
        for (SnakeBody snakeBody = mCauda; snakeBody != mHead; snakeBody = snakeBody.getNext()) {
            if (snakeBody.getPosition().equals(mHead.getPosition())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查某点是否与蛇身位置重叠。
     * @param point 要检查的点
     * @return 点与蛇身位置重叠则返回 true，否则返回 false
     */
    public boolean pointIsOnMe(Point point) {
        for (SnakeBody snakeBody = mCauda; snakeBody != null; snakeBody = snakeBody.getNext()) {
            if (snakeBody.getPosition().equals(point)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 转弯。
     * @param direction 方向
     */
    public void turn(int direction) {
        // 如果方向与当前方向相反(想要直接调头)，则直接返回
        if (Math.abs(direction - mDirection) == 2) {
            return;
        }

        mDirection = direction;
    }
}
